class HookCodeFactory {
  setup(instance, options){
    instance._x = options.taps.map(item => item.fn)
  }
  init(options){
    this.options = options;
  }

  deinit(){
    this.options = null;
  }

  args(options = {}){
    const {before, after} = options;
    let allArgs = this.options.args;
    if(befor){
      allArgs = [before,...allArgs]
    }
    if(after){
      allArgs = [...allArgs,after]
    }
    if(allArgs.length>0){
      return allArgs.join(',') 
    }
    return ''
  }
  header(){
    let code = ''
    code += `var _x = this._x;`
    return code
  }
  
  content(){
    this.callTapSeries(); // 以串形的方式调用tap函数 
  }

  create(options) {
    this.init(options)
    let fn;
    switch(options.type){
      case 'sync':
        fn = new Function(
          this.args(),
          this.header() + this.content()
        )
         break;
         case 'async':
          fn = new Function(
            this.args({
              after: '_callback'
            }),
            this.header() + this.content()
          )
           break;
      default:
        break;
    }
    this.deinit() 
    return fn
  }

  callTapSeries(){
    let taps = this.options.taps
    if(taps.length === 0){
      return ''
    }
    let code = '';
    for(let i = 0; i<taps.length; i++){
       code += this.callTap(i)
    }
    return code
  }

  callTapParallel(){
    let taps = this.options.taps
    let code = `var _counter = ${taps.length}`;
    code += `
      var _done=function(){
        _callabck()
      }
    `
    for(let i = 0; i<taps.length; i++){
       code += this.callTap(i)
    }
    return code
  }
  callTap(tapIndex){
    let code = ''
    code += `var _fn${tapIndex} = _x[${tapIndex}]`
    let tapInfo = this.options.taps[tapIndex]
    switch(tapInfo.type){
      case 'sync':
        code += `_fn${tapIndex}(${this.args()})`
        break;
      case 'async':
          code += `_fn${tapInfo}(${this.args({
            after:`function(){
              if(--_counter===0) _done()
            }`
          })})`
          break;
      default:
        break;
    }
    return code;

  }
}

module.exports = HookCodeFactory;